﻿using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CommunicationTools
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// 连接状态
        /// 0 未连接
        /// 1 RS232
        /// 2 TCP
        /// </summary>
        static int LinkedStatus = 0;

        SerialPort MyPort;
        Socket MySocket;
        IPEndPoint MyEndPoint;

        Socket MyServer;

        /// <summary>
        /// 连续发送开关
        /// </summary>
        bool SendContinue = false;
        /// <summary>
        /// 连续发送延迟
        /// </summary>
        int SendDelay = MinDelay;
        /// <summary>
        /// Socket用，连续接收开关
        /// </summary>
        bool ReceiveContinue = false;

        /// <summary>
        /// 最小延迟
        /// </summary>
        const int MinDelay = 100;

        SynchronizationContext Sync = SynchronizationContext.Current;

        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 搜索端口
        /// </summary>
        void SearchPort()
        {
            RegistryKey keyCom = Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm");
            if (keyCom != null)
            {
                string[] sSubKeys = keyCom.GetValueNames();
                ComboBoxCom.Items.Clear();
                foreach (string sName in sSubKeys)
                {
                    string sValue = (string)keyCom.GetValue(sName);
                    ComboBoxCom.Items.Add(sValue);
                }
                if (ComboBoxCom.Items.Count > 0) ComboBoxCom.SelectedIndex = 0;
            }
        }

        /// <summary>
        /// 搜索本地IP
        /// 参考 https://www.cnblogs.com/softwaredeveloper/p/5584728.html
        /// </summary>
        void SearchLocalIP()
        {
            try
            {
                IPAddress[] ipArray;
                ipArray = Dns.GetHostAddresses(Dns.GetHostName());
                //localIp = ipArray.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
                foreach(var ipaddr in ipArray)
                {
                    if (ipaddr.AddressFamily == AddressFamily.InterNetwork)
                    {//筛选IPv4的地址
                        ComboBoxLocalIP.Items.Add(ipaddr.ToString());
                    }
                }
            }
            catch
            {
                return;
            }
        }

        /// <summary>
        /// 打开串口
        /// </summary>
        void OpenPort()
        {
            if (LinkedStatus == 0)
            {
                try
                {
                    MyPort = new SerialPort();
                    MyPort.PortName = ComboBoxCom.Text;
                    MyPort.BaudRate = Convert.ToInt32(ComboBoxBaudRate.Text);
                    switch (ComboBoxParity.SelectedIndex)
                    {
                        default:
                            MyPort.Parity = Parity.None;
                            break;
                        case 1:
                            MyPort.Parity = Parity.Odd;
                            break;
                        case 2:
                            MyPort.Parity = Parity.Even;
                            break;
                    }
                    MyPort.DataBits = Convert.ToInt32(ComboBoxDataBits.Text);
                    switch (ComboBoxStopBits.SelectedIndex)
                    {
                        default:
                            MyPort.StopBits = StopBits.One;
                            break;
                        case 1:
                            MyPort.StopBits = StopBits.Two;
                            break;
                    }

                    MyPort.Open();
                    MyPort.DataReceived += SerialData_Received;
                    LinkedStatus = 1;
                    SnackbarMain.MessageQueue.Enqueue("打开串口成功");
                }
                catch
                {
                    ToggleButtonSerialOpen.IsChecked = false;
                    SnackbarMain.MessageQueue.Enqueue("打开串口失败");
                }
            }
            else
            {
                ToggleButtonSerialOpen.IsChecked = false;
                SnackbarMain.MessageQueue.Enqueue("打开串口失败");
            }
        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        void ClosePort()
        {
            if (LinkedStatus == 1)
            {
                try
                {
                    ToggleButtonContinue.IsChecked = false;

                    MyPort.Close();
                    MyPort.DataReceived -= SerialData_Received;

                    LinkedStatus = 0;
                    SnackbarMain.MessageQueue.Enqueue("关闭串口成功");
                }
                catch
                {
                    ToggleButtonSerialOpen.IsChecked = true;
                    SnackbarMain.MessageQueue.Enqueue("关闭串口失败");
                }
            }
            else
            {
                ToggleButtonSerialOpen.IsChecked = true ;
                SnackbarMain.MessageQueue.Enqueue("关闭串口失败");
            }
        }

        /// <summary>
        /// 接收串口数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SerialData_Received(object sender, SerialDataReceivedEventArgs e)
        {
            string str = MyPort.ReadExisting();
            Sync.Post((o) =>
            {
                TextBlockReceive.Text += "\n" + DateTime.Now.ToString();
                TextBlockReceive.Text += "\n" + str + "\n";
                ScrollViewerReceive.ScrollToBottom();
            }, null);
        }

        /// <summary>
        /// 接收Socket数据
        /// </summary>
        void SocketData_Received()
        {
            byte[] data = new byte[1024];
            while (ReceiveContinue)
            {
                try
                {
                    int recv = MySocket.Receive(data);
                    if (recv != 0)
                    {
                        string msg = Encoding.ASCII.GetString(data, 0, recv);
                        Sync.Post((o) =>
                        {
                            TextBlockReceive.Text += "\n" + DateTime.Now.ToString();
                            TextBlockReceive.Text += "\n" + msg + "\n";
                            ScrollViewerReceive.ScrollToBottom();
                        }, null);
                    }
                }
                catch
                {
                    return;
                }
            }
        }

        /// <summary>
        /// 串口发送
        /// </summary>
        void PortSend()
        {
            while (SendContinue)
            {
                Sync.Post((o) =>
                {
                    MyPort.Write(TextBoxInput.Text);
                }, null);
                Thread.Sleep(SendDelay);
            }
        }

        /// <summary>
        /// 网口发送
        /// </summary>
        void SocketSend()
        {
            while (SendContinue)
            {
                Sync.Post((o) =>
                {
                    MySocket.Send(Encoding.ASCII.GetBytes(TextBoxInput.Text));
                }, null);
                Thread.Sleep(SendDelay);
            }
        }

        /// <summary>
        /// 开启Socket
        /// </summary>
        void OpenSocket()
        {
            if (LinkedStatus == 0)
            {
                try
                {
                    switch (ComboBoxServer.SelectedIndex)
                    {
                        case 0:
                            {//开启客户端
                                MySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                                MyEndPoint = new IPEndPoint(IPAddress.Parse(TextBoxRemoteIP.Text), Convert.ToInt32(TextBoxRemotePort.Text));
                                MySocket.Connect(MyEndPoint);

                                ReceiveContinue = true;

                                //新建线程 https://www.cnblogs.com/huanjun/p/7831893.html
                                //拓展 https://www.cnblogs.com/gangle/p/9285094.html
                                Thread th = new Thread(new ThreadStart(SocketData_Received));
                                th.Start();

                                LinkedStatus = 2;
                                SnackbarMain.MessageQueue.Enqueue("打开Socket成功");
                            }
                            break;
                        case 1:
                            {//开启服务端
                                MyEndPoint = new IPEndPoint(IPAddress.Any, Convert.ToInt32(TextBoxLocalPort.Text));
                                MyServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                                MyServer.Bind(MyEndPoint);

                                SnackbarMain.MessageQueue.Enqueue("监听中");
                                ToggleButtonSocketOpen.IsEnabled = false;

                                Task.Factory.StartNew(() =>
                                {
                                    MyServer.Listen(10);

                                    MySocket = MyServer.Accept();
                                    IPEndPoint ip = (IPEndPoint)MySocket.RemoteEndPoint;

                                    Sync.Post((o) =>
                                    {
                                        TextBlockLinked.Text = ip.Address.ToString() + ":" + ip.Port.ToString();

                                        SnackbarMain.MessageQueue.Enqueue("打开Socket成功");
                                        ToggleButtonSocketOpen.IsEnabled = true;
                                    }, null);

                                    ReceiveContinue = true;
                                    Thread th = new Thread(new ThreadStart(SocketData_Received));
                                    th.Start();

                                    LinkedStatus = 2;
                                });
                            }
                            break;
                    }
                }
                catch
                {
                    ToggleButtonSocketOpen.IsChecked = false;
                    SnackbarMain.MessageQueue.Enqueue("打开Socket失败");
                }
            }
            else
            {
                ToggleButtonSocketOpen.IsChecked = false;
                SnackbarMain.MessageQueue.Enqueue("打开Socket失败");
            }
        }

        /// <summary>
        /// 关闭Socket
        /// </summary>
        void CloseSocket()
        {
            if (LinkedStatus == 2)
            {
                try
                {
                    ReceiveContinue = false;
                    ToggleButtonContinue.IsChecked = false;

                    switch (ComboBoxServer.SelectedIndex)
                    {
                        case 0://关闭客户端
                            MySocket.Shutdown(SocketShutdown.Both);
                            MySocket.Close();
                            break;
                        case 1://关闭服务端
                            MySocket.Close();
                            MyServer.Close();
                            break;
                    }

                    TextBlockLinked.Text = "";
                    LinkedStatus = 0;
                    SnackbarMain.MessageQueue.Enqueue("关闭Socket成功");
                }
                catch
                {
                    ToggleButtonSocketOpen.IsChecked = true;
                    SnackbarMain.MessageQueue.Enqueue("关闭Socket失败");
                }
            }
            else
            {
                ToggleButtonSocketOpen.IsChecked = true;
                SnackbarMain.MessageQueue.Enqueue("关闭Socket失败");
            }
        }

        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var mySender = sender as ComboBox;
            switch (mySender.Name)
            {
                case "ComboBoxTools":
                    {
                        StackPanelSideSerial.Visibility = Visibility.Collapsed;
                        StackPanelSideSocket.Visibility = Visibility.Collapsed;
                        switch (mySender.SelectedIndex)
                        {
                            case 0://进入串口
                                {
                                    StackPanelSideSerial.Visibility = Visibility.Visible;
                                    SearchPort();
                                }
                                break;
                            case 1://进入Socket
                                {
                                    StackPanelSideSocket.Visibility = Visibility.Visible;
                                    SearchLocalIP();
                                }
                                break;
                        }
                    }
                    break;
                case "ComboBoxServer":
                    {//切换客户端服务端
                        switch (mySender.SelectedIndex)
                        {
                            case 0:
                                {//客户端
                                    ComboBoxLocalIP.IsEnabled = false;
                                    TextBoxLocalPort.IsEnabled = false;
                                    TextBoxRemoteIP.IsEnabled = true;
                                    TextBoxRemotePort.IsEnabled = true;
                                }
                                break;
                            case 1:
                                {//服务端
                                    TextBoxRemoteIP.IsEnabled = false;
                                    TextBoxRemotePort.IsEnabled = false;
                                    ComboBoxLocalIP.IsEnabled = true;
                                    TextBoxLocalPort.IsEnabled = true;
                                }
                                break;
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var mySender = sender as Button;
            switch (mySender.Name)
            {
                case "ButtonSerialClean":
                case "ButtonSocketClean":
                    {
                        TextBlockReceive.Text = "";
                    }
                    break;
                case "ButtonSend":
                    {
                        switch (LinkedStatus)
                        {
                            default:
                                SnackbarMain.MessageQueue.Enqueue("未打开连接");
                                break;
                            case 1:
                                {//串口发送
                                    try
                                    {
                                        if (MyPort.IsOpen)
                                        {
                                            MyPort.Write(TextBoxInput.Text);
                                        }
                                        else
                                        {
                                            SnackbarMain.MessageQueue.Enqueue("未打开连接");
                                        }
                                    }
                                    catch
                                    {
                                        SnackbarMain.MessageQueue.Enqueue("发送失败");
                                    }
                                }
                                break;
                            case 2:
                                {//网口发送
                                    try
                                    {
                                        if (LinkedStatus == 2)
                                        {
                                            MySocket.Send(Encoding.ASCII.GetBytes(TextBoxInput.Text));
                                        }
                                        else
                                        {
                                            SnackbarMain.MessageQueue.Enqueue("未打开连接");
                                        }
                                    }
                                    catch
                                    {
                                        SnackbarMain.MessageQueue.Enqueue("发送失败");
                                    }
                                }
                                break;
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        private void ToggleButton_Checked(object sender, RoutedEventArgs e)
        {
            var mySender = sender as ToggleButton;
            switch (mySender.Name)
            {
                case "ToggleButtonSerialOpen":
                    {//开启串口
                        if (mySender.IsChecked==true)
                        {
                            ComboBoxTools.IsEnabled = false;

                            ComboBoxCom.IsEnabled = false;
                            ComboBoxDataBits.IsEnabled = false;
                            ComboBoxParity.IsEnabled = false;
                            ComboBoxBaudRate.IsEnabled = false;
                            ComboBoxStopBits.IsEnabled = false;

                            if (LinkedStatus == 0) OpenPort();
                            else mySender.IsChecked = false;
                        }
                        else
                        {
                            ComboBoxTools.IsEnabled = true;

                            ComboBoxCom.IsEnabled = true;
                            ComboBoxDataBits.IsEnabled = true;
                            ComboBoxParity.IsEnabled = true;
                            ComboBoxBaudRate.IsEnabled = true;
                            ComboBoxStopBits.IsEnabled = true;

                            if (LinkedStatus == 1) ClosePort();
                        }
                    }
                    break;
                case "ToggleButtonSocketOpen":
                    {//开启Socket
                        if (mySender.IsChecked == true)
                        {
                            ComboBoxTools.IsEnabled = false;
                            ComboBoxServer.IsEnabled = false;

                            switch (ComboBoxServer.SelectedIndex)
                            {
                                default:
                                    {
                                        ComboBoxTools.IsEnabled = true;
                                        ComboBoxServer.IsEnabled = true;
                                        SnackbarMain.MessageQueue.Enqueue("未选择服务/客户端");

                                        mySender.IsChecked = false;
                                    }
                                    break;
                                case 0:
                                    {
                                        TextBoxRemoteIP.IsEnabled = false;
                                        TextBoxRemotePort.IsEnabled = false;
                                    }
                                    break;
                                case 1:
                                    {
                                        //ComboBoxLocalIP.IsEnabled = false;
                                        TextBoxLocalPort.IsEnabled = false;
                                    }
                                    break;
                            }

                            if (LinkedStatus == 0) OpenSocket();
                            else mySender.IsChecked = false;
                        }
                        else
                        {
                            ComboBoxTools.IsEnabled = true;
                            ComboBoxServer.IsEnabled = true;

                            switch (ComboBoxServer.SelectedIndex)
                            {
                                case 0:
                                    TextBoxRemoteIP.IsEnabled = true;
                                    TextBoxRemotePort.IsEnabled = true;
                                    break;
                                case 1:
                                    //ComboBoxLocalIP.IsEnabled = true;
                                    TextBoxLocalPort.IsEnabled = true;
                                    break;
                            }

                            if (LinkedStatus == 2) CloseSocket();
                        }
                    }
                    break;
                case "ToggleButtonContinue":
                    {//连续发送
                        switch (LinkedStatus)
                        {
                            default:
                                {//未连接状态
                                    if (mySender.IsChecked == true)
                                    {
                                        SnackbarMain.MessageQueue.Enqueue("未打开连接");
                                        ToggleButtonContinue.IsChecked = false;
                                    }
                                }
                                break;
                            case 1:
                                {//串口连接状态
                                    if (mySender.IsChecked == true)
                                    {
                                        try
                                        {
                                            SendDelay = Convert.ToInt32(TextBoxDelay.Text);
                                            SendDelay = SendDelay > MinDelay ? SendDelay : MinDelay;
                                            SendContinue = true;

                                            TextBoxDelay.IsEnabled = false;

                                            //新建线程 https://www.cnblogs.com/huanjun/p/7831893.html
                                            //拓展 https://www.cnblogs.com/gangle/p/9285094.html
                                            Thread th = new Thread(new ThreadStart(PortSend));
                                            th.Start();
                                        }
                                        catch
                                        {
                                            TextBoxDelay.IsEnabled = true;

                                            SendDelay = MinDelay;
                                            SendContinue = false;
                                            SnackbarMain.MessageQueue.Enqueue("连续发送失败");
                                        }
                                    }
                                    else
                                    {
                                        TextBoxDelay.IsEnabled = true;
                                        SendDelay = MinDelay;
                                        SendContinue = false;
                                    }
                                }
                                break;
                            case 2:
                                {//网口连接状态
                                    if (mySender.IsChecked == true)
                                    {
                                        try
                                        {
                                            SendDelay = Convert.ToInt32(TextBoxDelay.Text);
                                            SendDelay = SendDelay > MinDelay ? SendDelay : MinDelay;
                                            SendContinue = true;

                                            TextBoxDelay.IsEnabled = false;

                                            //新建线程 https://www.cnblogs.com/huanjun/p/7831893.html
                                            //拓展 https://www.cnblogs.com/gangle/p/9285094.html
                                            Thread th = new Thread(new ThreadStart(SocketSend));
                                            th.Start();
                                        }
                                        catch
                                        {
                                            TextBoxDelay.IsEnabled = true;

                                            SendDelay = MinDelay;
                                            SendContinue = false;
                                            SnackbarMain.MessageQueue.Enqueue("连续发送失败");
                                        }
                                    }
                                    else
                                    {
                                        TextBoxDelay.IsEnabled = true;
                                        SendDelay = MinDelay;
                                        SendContinue = false;
                                    }
                                }
                                break; 
                        }
                    }
                    break;
            }
        }
    }
}
